package org.medusa.buffer;

public abstract class Buffer /*implements ByteBuffer*/ {

	public Buffer() {}

	public abstract void Clear();
	
	public abstract boolean IsFull();
    
	public abstract boolean IsEmpty();
    
	// length
	public abstract int BufferSize();

	public abstract int DataSize();

	public abstract int FreeSize();

	public abstract int LineDataSize();

	public abstract int LineFreeSize();

	// Int8
	public abstract byte ReadInt8();

	public abstract void WriteInt8(byte val);

	// Boolean
	public boolean ReadBoolean() {
		return this.ReadInt8() != 0;
	}

	public void WriteBoolean(boolean val) {
		this.WriteInt8(((byte) (val ? 1 : 0)));
	}

	// Int16
	public short ReadInt16LE() {
		short accum = 0;

		accum |= (this.ReadInt8() & 0xff);
		accum |= (this.ReadInt8() & 0xff) << 8;

		return accum;
	}

	public void WriteInt16LE(int val) {
		this.WriteInt8((byte) val);
		this.WriteInt8((byte) (val >>> 8));
	}

	public short ReadInt16BE() {
		short accum = 0;

		accum |= (this.ReadInt8() & 0xff) << 8;
		accum |= (this.ReadInt8() & 0xff);

		return accum;
	}

	public void WriteInt16BE(int val) {
		this.WriteInt8((byte) (val >>> 8));
		this.WriteInt8((byte) val);
	}

	// Int32
	public int ReadInt32LE() {
		int accum = 0;

		accum |= (this.ReadInt8() & 0xff);
		accum |= (this.ReadInt8() & 0xff) << 8;
		accum |= (this.ReadInt8() & 0xff) << 16;
		accum |= (this.ReadInt8() & 0xff) << 24;

		return accum;
	}

	public void WriteInt32LE(int val) {
		this.WriteInt8((byte) (val));
		this.WriteInt8((byte) (val >>> 8));
		this.WriteInt8((byte) (val >>> 16));
		this.WriteInt8((byte) (val >>> 24));
	}

	public int ReadInt32BE() {
		int accum = 0;

		accum |= (this.ReadInt8() & 0xff) << 24;
		accum |= (this.ReadInt8() & 0xff) << 16;
		accum |= (this.ReadInt8() & 0xff) << 8;
		accum |= (this.ReadInt8() & 0xff);

		return accum;
	}

	public void WriteInt32BE(int val) {
		this.WriteInt8((byte) (val >>> 24));
		this.WriteInt8((byte) (val >>> 16));
		this.WriteInt8((byte) (val >>> 8));
		this.WriteInt8((byte) (val));
	}

	// Int64
	public long ReadInt64LE() {
		long accum = 0;

		accum |= (long) (this.ReadInt8() & 0xff);
		accum |= (long) (this.ReadInt8() & 0xff) << 8;
		accum |= (long) (this.ReadInt8() & 0xff) << 16;
		accum |= (long) (this.ReadInt8() & 0xff) << 24;
		accum |= (long) (this.ReadInt8() & 0xff) << 32;
		accum |= (long) (this.ReadInt8() & 0xff) << 40;
		accum |= (long) (this.ReadInt8() & 0xff) << 48;
		accum |= (long) (this.ReadInt8() & 0xff) << 56;

		return accum;
	}

	public void WriteInt64LE(long val) {
		this.WriteInt8((byte) (val));
		this.WriteInt8((byte) (val >>> 8));
		this.WriteInt8((byte) (val >>> 16));
		this.WriteInt8((byte) (val >>> 24));
		this.WriteInt8((byte) (val >>> 32));
		this.WriteInt8((byte) (val >>> 40));
		this.WriteInt8((byte) (val >>> 48));
		this.WriteInt8((byte) (val >>> 56));
	}

	public long ReadInt64BE() {
		long accum = 0;

		accum |= (long) (this.ReadInt8() & 0xff) << 56;
		accum |= (long) (this.ReadInt8() & 0xff) << 48;
		accum |= (long) (this.ReadInt8() & 0xff) << 40;
		accum |= (long) (this.ReadInt8() & 0xff) << 32;
		accum |= (long) (this.ReadInt8() & 0xff) << 24;
		accum |= (long) (this.ReadInt8() & 0xff) << 16;
		accum |= (long) (this.ReadInt8() & 0xff) << 8;
		accum |= (long) (this.ReadInt8() & 0xff);

		return accum;
	}

	public void WriteInt64BE(long val) {
		this.WriteInt8((byte) (val >>> 56));
		this.WriteInt8((byte) (val >>> 48));
		this.WriteInt8((byte) (val >>> 40));
		this.WriteInt8((byte) (val >>> 32));
		this.WriteInt8((byte) (val >>> 24));
		this.WriteInt8((byte) (val >>> 16));
		this.WriteInt8((byte) (val >>> 8));
		this.WriteInt8((byte) (val));
	}

	// Float32
	public float ReadFloat32LE() {
		int accum = this.ReadInt32LE();
		return Float.intBitsToFloat(accum);
	}

	public void WriteFloat32LE(float val) {
		int accum = Float.floatToRawIntBits(val);
		this.WriteInt32LE(accum);
	}

	public float ReadFloat32BE() {
		int accum = this.ReadInt32BE();
		return Float.intBitsToFloat(accum);
	}

	public void WriteFloat32BE(float val) {
		int accum = Float.floatToRawIntBits(val);
		this.WriteInt32BE(accum);
	}

	// Float64
	public double ReadFloat64LE() {
		long accum = this.ReadInt64LE();
		return Double.longBitsToDouble(accum);
	}

	public void WriteFloat64LE(double val) {
		long accum = Double.doubleToRawLongBits(val);
		this.WriteInt64LE(accum);
	}

	public double ReadFloat64BE() {
		long accum = this.ReadInt64BE();
		return Double.longBitsToDouble(accum);
	}

	public void WriteFloat64BE(double val) {
		long accum = Double.doubleToRawLongBits(val);
		this.WriteInt64BE(accum);
	}

	// Line
	public String ReadLine(byte lineend) {
		int line_size = 1024;
		byte[] line = new byte[line_size];
		int line_index = 0;
		while (true) {
			// 防御
			if (line_index == line_size) {
				int new_line_size = line_size + 1024;
				byte[] new_line = new byte[new_line_size];
				System.arraycopy(line, 0, new_line, 0, line_index);
				line_size = new_line_size;
				line = new_line;
			}
			// read
			line[line_index] = this.ReadInt8();
			if (line[line_index] == lineend)
				break;
			line_index++;
		}

		return new String(line, 0, line_index);
		/*
		 * String ret=""; try { ret = new String(bytes, 0, index, "UTF8"); }
		 * catch (UnsupportedEncodingException e) { e.printStackTrace(); } // ,
		 * "Unicode" return ret;
		 */
	}

	public void WriteLine(String val, byte lineend) {
		byte[] str = val.getBytes();
		for (int i = 0; i < str.length; i++) {
			this.WriteInt8(str[i]);
		}
		this.WriteInt8(lineend);
	}
	
	public void ReadLine(Buffer dst, byte lineend) {
		byte b;
		while (!this.IsEmpty()) {
			b = this.ReadInt8();
			dst.WriteInt8(b);
			if (b == lineend)
				break;
		}
	}

	public void WriteLine(Buffer src, byte lineend) {
		src.ReadLine(this, lineend);
	}

	// String
	public String ReadString() {
		int size = this.ReadInt16BE();
		if (size > 0) {
			String val = new String(this.ReadBlob(size), 0, size);
			return val;
		}

		return "";
	}

	public void WriteString(String val) {
		int size = val.getBytes().length;
		this.WriteInt16BE(size);

		byte[] str = val.getBytes();
		for (int i = 0; i < str.length; i++) {
			this.WriteInt8(str[i]);
		}
	}

	public void WriteString() {
		this.WriteInt16BE(0);
	}

	// bytes
	public void ReadBlob(byte[] dst, int size) {
		for (int i = 0; i < size; i++) {
			dst[i] = this.ReadInt8();
		}
	}

	public byte[] ReadBlob(int size) {
		byte[] dst = new byte[size];
		for (int i = 0; i < size; i++) {
			dst[i] = this.ReadInt8();
		}
		return dst;
	}

	public void WriteBlob(String val) {
		byte[] bytes = val.getBytes();
		for (int i = 0; i < bytes.length; i++) {
			this.WriteInt8(bytes[i]);
		}
	}
	
	public void WriteBlob(byte[] src, int size) {
		for (int i = 0; i < size; i++) {
			this.WriteInt8(src[i]);
		}
	}

	public void ReadBuffer(Buffer dst, int size) {
		for (int i = 0; i < size; i++) {
			dst.WriteInt8(this.ReadInt8());
		}
	}

	public void WriteBuffer(Buffer src, int size) {
		for (int i = 0; i < size; i++) {
			this.WriteInt8(src.ReadInt8());
		}
	}

}
